﻿using System;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.IO;
using GosafeTest;
using System.Reflection;

namespace SIGGREProto
{
    class Server
    {
        private TcpListener tcpListener;
        private Thread listenThread;

        TcpClient clientGosafeServer;

        private AsyncCallback receiveCallbackDelegate;

        //NetworkStream gosafeServerStream;

        byte[] serverResponse;

        //NetworkStream deviceClient;

        //private TCPServer.LogDatabase logDatabase;
        private Thread logThread;

        private string ipProvider = "http://automation.whatismyip.com/n09230945.asp";

        // Delegate that defines the signature for the callback method.
        //
        public delegate void ExampleCallback(int lineCount);
        public delegate void CurrentIP(string IPAddress);

        TcpClient currentConnectedClient = null;

        public int debugLevel = 0;
        public bool sendAck = false;

        // end-of-message chars
        public const int END_OF_MESSAGE_CHAR1 = 10;
        public const int END_OF_MESSAGE_CHAR2 = 13;

        public Server()
        {
            Console.WriteLine(DateTime.Now + " SIGGRE Server version " +
                Assembly.GetExecutingAssembly().GetName().Version);

            this.tcpListener = new TcpListener(IPAddress.Any, 3030);
            string IPinternet = IPMonitor.GetExternalIP(ipProvider);
            Console.WriteLine(DateTime.Now + " Listening on port 3030 ");
            Console.WriteLine(DateTime.Now + " Remote address: " + IPinternet);
            Console.WriteLine(DateTime.Now + " Local adress: " + IPMonitor.GetLocalIP());

            //this.logDatabase = new TCPServer.LogDatabase(IPMonitor.GetLocalIP());

            this.listenThread = new Thread(new ThreadStart(ListenForClients));
            this.listenThread.Start();

        }

        private void ListenForClients()
        {
            this.tcpListener.Start();

            TcpClient client;

            while (true)
            {
                //blocks until a client has connected to the server
                client = this.tcpListener.AcceptTcpClient();
                currentConnectedClient = client;

                Console.WriteLine(DateTime.Now + " Accepted connection from " + client.Client.RemoteEndPoint.ToString());

                //create a thread to handle communication
                //with connected client
                Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
                clientThread.Start(client);
            }

            Console.WriteLine(DateTime.Now + " client disconnected : " + client.Client.RemoteEndPoint.ToString());

        }

        private void HandleClientComm(object client)
        {
            TCPServer.LogDatabase logDatabase = new TCPServer.LogDatabase(IPMonitor.GetLocalIP());
            
            TcpClient tcpClient = (TcpClient)client;
            NetworkStream deviceClient = tcpClient.GetStream();
            //deviceClient = tcpClient.GetStream();

            //NetworkStream gosafeServerStream = clientGosafeServer.GetStream();
            //gosafeServerStream = clientGosafeServer.GetStream();

            //byte[] message = new byte[8192];
            int bytesRead;

            byte[] completeMessage = new byte[8192];

            int totalBytesRead = 0;

            while (true)
            {
                bytesRead = 0;
                byte[] message = new byte[8192];

                try
                {
                    //blocks until a client sends a message
                    bytesRead = deviceClient.Read(message, 0, 8192);
                }
                catch
                {
                    //a socket error has occured
                    Console.WriteLine(DateTime.Now + " Error reading message from : " + tcpClient.Client.RemoteEndPoint.ToString());
                    break;
                }

                if (bytesRead == 0)
                {
                    //the client has disconnected from the server
                    Console.WriteLine(DateTime.Now + " Zero Bytes read - client disconnected : " + tcpClient.Client.RemoteEndPoint.ToString());
                    break;
                }

                //message has successfully been received
                ASCIIEncoding encoder = new ASCIIEncoding();
                System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead));

                if(debugLevel>0)
                    Console.WriteLine(DateTime.Now + " : byte received - <" + encoder.GetString(message, 0, bytesRead) + ">");

                byte[] messageShort = new byte[bytesRead];
                Array.Copy(message, messageShort, bytesRead);

                // Append bytes read to the full message
                Array.Copy(message, 0, completeMessage, totalBytesRead, bytesRead);

                totalBytesRead += bytesRead;

                //this.logDatabase.IPDeviceEmbedded = currentConnectedClient.Client.RemoteEndPoint.ToString();
                logDatabase.IPDeviceEmbedded = tcpClient.Client.RemoteEndPoint.ToString();
                //this.logDatabase.setDataAvaiable(messageShort, true);
                
                //logDatabase.setDataAvaiable(messageShort, true);

                //Console.WriteLine(DateTime.Now + " Received " + bytesRead + " bytes from : <" + tcpClient.Client.RemoteEndPoint.ToString() + ">");
                //Console.WriteLine(DateTime.Now + " Bytes Received: " + BitConverter.ToString(message, 0, bytesRead));

                // message ended by CR + LF or end-of-message chars
                if ((message[bytesRead - 1] == END_OF_MESSAGE_CHAR1 && message[bytesRead - 2] == END_OF_MESSAGE_CHAR2))
                {
                    ASCIIEncoding completeEncoder = new ASCIIEncoding();
                    System.Diagnostics.Debug.WriteLine(completeEncoder.GetString(completeMessage, 0, totalBytesRead));
                    Console.WriteLine(DateTime.Now + "  Received EOM chars.: Message completed - bytes received - <" + 
                        completeEncoder.GetString(completeMessage, 0, totalBytesRead) + ">");

                    totalBytesRead = 0;
                    completeMessage = new byte[8192];

                    //break;

                    if (sendAck)
                    {
                        NetworkStream clientStream = tcpClient.GetStream();
                        clientStream.Write(completeMessage, 0, totalBytesRead);
                        clientStream.Flush();
                    }
                }
                                
            }

            Console.WriteLine(DateTime.Now + " Client Thread ended - closing connection from : " + tcpClient.Client.RemoteEndPoint.ToString());
            //tcpClient.Close();
        }

    }

}


